/*
 * Powered By XY
 * Since 2020
 */

package com.xy.biz.base.client;

import com.xy.biz.base.domain.dto.DictDTO;
import com.xy.biz.base.domain.req.*;
import com.xy.biz.base.domain.resp.ListDictItemResponse;
import com.xy.lang.domain.Result;
import com.xy.lang.util.ResultUtils;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 *
 *
 * @author zsp
 * @date 2020-5-23
 */
public interface DictClient {

    Result<?> saveDictAutoCode(SaveDictRequest request);

    Result<ListDictItemResponse> getDictItem(GetDictByCodeRequest request);


    Result<List<ListDictItemResponse>> listDictItem(ListDictItemRequest request);

    Result<DictDTO> getDict(GetDictRequest request);

    Result<?> updateDict(SaveDictRequest request);

    Result<?> updateAll(UpdateDictAllRequest request);

    String getValue(String code);


    Result<?> deleteDict(GetDictRequest request);


    Result<?> deleteDictNoVerify(GetDictRequest request);


    /// default methods

    default Result<String> getDictValue(GetDictByCodeRequest request) {
        ListDictItemResponse response = ResultUtils.get(getDictItem(request));
        return response == null ? Result.success() : Result.success(response.getDictValue());
    }

    default Result<Integer> getDictIntValue(GetDictByCodeRequest request) {
        ListDictItemResponse response = ResultUtils.get(getDictItem(request));
        return response == null ? Result.success() : ResultUtils.getValueResult(response.getDictValue(), Integer::parseInt);
    }

    default Result<Long> getDictLongValue(GetDictByCodeRequest request) {
        ListDictItemResponse response = ResultUtils.get(getDictItem(request));
        return response == null ? Result.success() : ResultUtils.getValueResult(response.getDictValue(), Long::parseLong);
    }

    default Result<Float> getDictFloatValue(GetDictByCodeRequest request) {
        ListDictItemResponse response = ResultUtils.get(getDictItem(request));
        return response == null ? Result.success() : ResultUtils.getValueResult(response.getDictValue(), Float::parseFloat);
    }

    default Result<Double> getDictDoubleValue(GetDictByCodeRequest request) {
        ListDictItemResponse response = ResultUtils.get(getDictItem(request));
        return response == null ? Result.success() : ResultUtils.getValueResult(response.getDictValue(), Double::parseDouble);
    }

    default Result<BigDecimal> getDictBigDecimalValue(GetDictByCodeRequest request) {
        ListDictItemResponse response = ResultUtils.get(getDictItem(request));
        return response == null ? Result.success() : ResultUtils.getValueResult(response.getDictValue(), BigDecimal::new);
    }

    default Result<List<String>> listDictValue(ListDictItemRequest request) {
        List<ListDictItemResponse> list = ResultUtils.get(listDictItem(request));
        return (null == null || list.size() == 0)
                ? Result.success()
                : Result.success(list.stream().map(e -> e.getDictValue()).collect(Collectors.toList()));
    }

    default Result<List<Integer>> listDictIntValue(ListDictItemRequest request) {
        List<ListDictItemResponse> list = ResultUtils.get(listDictItem(request));
        return (null == null || list.size() == 0)
                ? Result.success()
                : Result.success(list.stream().map(e -> Integer.parseInt(e.getDictValue())).collect(Collectors.toList()));
    }

    default Result<List<Long>> listDictLongValue(ListDictItemRequest request) {
        List<ListDictItemResponse> list = ResultUtils.get(listDictItem(request));
        return (null == null || list.size() == 0)
                ? Result.success()
                : Result.success(list.stream().map(e -> Long.parseLong(e.getDictValue())).collect(Collectors.toList()));
    }

    default Result<List<Float>> listDictFloatValue(ListDictItemRequest request) {
        List<ListDictItemResponse> list = ResultUtils.get(listDictItem(request));
        return (null == null || list.size() == 0)
                ? Result.success()
                : Result.success(list.stream().map(e -> Float.parseFloat(e.getDictValue())).collect(Collectors.toList()));
    }

    default Result<List<Double>> listDictDoubleValue(ListDictItemRequest request) {
        List<ListDictItemResponse> list = ResultUtils.get(listDictItem(request));
        return (null == null || list.size() == 0)
                ? Result.success()
                : Result.success(list.stream().map(e -> Double.parseDouble(e.getDictValue())).collect(Collectors.toList()));
    }

    default Result<List<BigDecimal>> listDictBigDecimalValue(ListDictItemRequest request) {
        List<ListDictItemResponse> list = ResultUtils.get(listDictItem(request));
        return (null == null || list.size() == 0)
                ? Result.success()
                : Result.success(list.stream().map(e -> new BigDecimal(e.getDictValue())).collect(Collectors.toList()));
    }

    default Map<String, String> mapDict(String dictGroupCode) {
        List<ListDictItemResponse> dictItemResponses
                = listDictItem(ListDictItemRequest.builder()
                    .dictGroupCode(dictGroupCode)
                    .build())
                .getData();
        return dictItemResponses.stream().collect(
                Collectors.toMap(item -> item.getDictCode(), item -> item.getDictValue()));
    }

    default <T> void buildByDict(Collection<T> originCollection,
                                 String dictGroupCode,
                                 Function<T, String> codeGetter,
                                 BiConsumer<T, String> valueSetter) {
        List<ListDictItemResponse> dictItemResponses
                = listDictItem(ListDictItemRequest.builder()
                    .dictGroupCode(dictGroupCode)
                    .parentDictId(0L)
                    .build())
                .getData();
        Map<String, String> dictMap = dictItemResponses.stream().collect(
                Collectors.toMap(item -> item.getDictCode(), item -> item.getDictValue()));
        for (T t : originCollection) {
            valueSetter.accept(t, dictMap.get(codeGetter.apply(t)));
        }
    }
}
